package info.batcloud.fanli.core.service.impl;

import com.ctospace.archit.common.pagination.Paging;
import info.batcloud.fanli.core.dto.UserRedPacketDTO;
import info.batcloud.fanli.core.entity.RedPacket;
import info.batcloud.fanli.core.entity.User;
import info.batcloud.fanli.core.entity.UserRedPacket;
import info.batcloud.fanli.core.exception.BizException;
import info.batcloud.fanli.core.repository.RedPacketRepository;
import info.batcloud.fanli.core.repository.UserRedPacketRepository;
import info.batcloud.fanli.core.repository.UserRepository;
import info.batcloud.fanli.core.service.UserRedPacketService;
import info.batcloud.fanli.core.service.WalletService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserRedPacketServiceImpl implements UserRedPacketService {

    @Inject
    private UserRedPacketRepository userRedPacketRepository;

    @Inject
    private RedPacketRepository redPacketRepository;

    @Inject
    private UserRepository userRepository;

    @Inject
    private WalletService walletService;

    @Override
    public Paging<UserRedPacketDTO> search(SearchParam param) {
        Specification<UserRedPacket> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            if (param.getDraw() != null) {
                expressions.add(cb.equal(root.get("draw"), param.getDraw()));
            }
            if (param.getRedPacketId() != null) {
                expressions.add(cb.equal(root.get("redPacket").get("id"), param.getRedPacketId()));
            }
            if (param.getUserId() != null) {
                expressions.add(cb.equal(root.get("user").get("id"), param.getUserId()));
            }
            return predicate;
        };
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<UserRedPacket> page = userRedPacketRepository.findAll(specification, pageable);
        List<UserRedPacketDTO> dtoList = page.getContent().stream()
                .map(o -> toBO(o)).collect(Collectors.toList());
        return Paging.of(dtoList, Long.valueOf(page.getTotalElements()).intValue(),
                param.getPage(), param.getPageSize());
    }

    @Override
    public void addUserRedPacket(UserRedPacketAddParam param) {
        RedPacket redPacket = redPacketRepository.findOne(param.getRedPacketId());
        UserRedPacket userRedPacket = new UserRedPacket();
        userRedPacket.setCreateTime(new Date());
        userRedPacket.setDraw(false);
        userRedPacket.setIntegral(redPacket.getIntegral());
        userRedPacket.setMoney(redPacket.getMoney());
        userRedPacket.setUser(userRepository.findOne(param.getUserId()));
        userRedPacket.setRedPacket(redPacket);
        userRedPacketRepository.save(userRedPacket);
    }

    @Override
    @Transactional
    public synchronized void drawByIdAndUserId(long id, long userId) {
        UserRedPacket userRedPacket = userRedPacketRepository.findOne(id);
        User user = userRedPacket.getUser();
        if (!user.getId().equals(userId)) {
            throw new BizException("错误");
        }
        if (userRedPacket.isDraw()) {
            return;
        }
        userRedPacket.setDraw(true);
        RedPacket redPacket = userRedPacket.getRedPacket();
        if (userRedPacket.getMoney() > 0) {
            walletService.addMoney(user.getId(), userRedPacket.getMoney(), redPacket.getMoneyWalletFlowDetailType(), null);
        }
        if (userRedPacket.getIntegral() > 0) {
            walletService.addIntegral(user.getId(), userRedPacket.getIntegral(), redPacket.getIntegralWalletFlowDetailType(), null);
        }
        redPacket.setDrawNum(redPacket.getDrawNum() + 1);
        redPacket.setLastDrawTime(new Date());
        userRedPacketRepository.save(userRedPacket);
        redPacketRepository.save(redPacket);
    }

    private UserRedPacketDTO toBO(UserRedPacket userRedPacket) {
        UserRedPacketDTO bo = new UserRedPacketDTO();
        BeanUtils.copyProperties(userRedPacket, bo);
        bo.setUserId(userRedPacket.getUser().getId());
        bo.setUserNickname(userRedPacket.getUser().getNickname());
        RedPacket redPacket = userRedPacket.getRedPacket();
        bo.setRedPacketId(redPacket.getId());
        bo.setRedPacketName(redPacket.getName());
        bo.setRedPacketDescription(redPacket.getDescription());
        return bo;
    }
}
